﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.ExceptionManagement;

using DiscussionFieldNames = Kiiro.Common.Utility.Constants.DiscussionFieldNames;
using SPListNames = Kiiro.Common.Utility.Constants.SPListNames;

namespace Kiiro.DataAccess
{
    public class DiscussionDA
    {
        #region Singleton
        private DiscussionDA ( )
        {
        }

        private static DiscussionDA instance = null;
        private static readonly object threadLock = new object ( );

        public static DiscussionDA Instance
        {
            get
            {
                lock ( threadLock )
                {
                    if ( instance == null )
                    {
                        instance = new DiscussionDA ( );
                    }
                }
                return instance;
            }
        }
        #endregion

        /// <summary>
        /// Gets a list of Discussion entities. If discussionIds is null or empty this method returns ALL Discussions.
        /// </summary>
        /// <param name="discussionIds">The list of discussion ids to get. If discussionIds is null or empty this method returns ALL discussions.</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        /// <returns>If discussionIds is null or empty this method returns ALL discussions.</returns>
        public List<Discussion> GetDiscussionsByIds ( List<int> discussionIds, Guid siteCollectionId, string serverRelativeUrl )
        {
            return GetDiscussionsByIds( discussionIds, siteCollectionId, serverRelativeUrl, true );
        }

        /// <summary>
        /// Gets a list of Discussion entities. If discussionIds is null or empty this method returns ALL Discussions.
        /// </summary>
        /// <param name="discussionIds">The list of discussion ids to get. If discussionIds is null or empty this method returns ALL discussions.</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        /// <returns>If discussionIds is null or empty this method returns ALL discussions.</returns>
        public List<Discussion> GetDiscussionsByIds ( List<int> discussionIds, Guid siteCollectionId, string serverRelativeUrl, bool loadComments )
        {
            List<Discussion> discussions = new List<Discussion>( );
            SPList list = null;

            using ( SPWeb web = SPHelpers.GetWeb( siteCollectionId, serverRelativeUrl ) )
            {
                list = web.Lists[SPListNames.Discussions];

                if (list != null)
                {
                    SPQuery query = new SPQuery();

                    bool first = true;
                    if (discussionIds != null && discussionIds.Count > 0)
                    {
                        foreach (int discussionId in discussionIds)
                        {
                            if (!first) query.Query = "<Or>" + query.Query;
                            query.Query += "<Eq><FieldRef Name='ID'/><Value Type='Integer'>" + discussionId + "</Value></Eq>";
                            if (!first) query.Query += "</Or>";

                            first = false;
                        }
                    }

                    if (!string.IsNullOrEmpty(query.Query))
                        query.Query = "<Where>" + query.Query + "</Where>";

                    query.Query = query.Query + "<OrderBy> <FieldRef Name='" 
                                                            + DiscussionFieldNames.LastCommentDate + 
                                                            "' Ascending='false' />"+
                                                            "<FieldRef Name='" + DiscussionFieldNames.CreatedDate + "' Ascending='false' />" +
                                                "</OrderBy>";
                    SPListItemCollection listItems = list.GetItems(query);
                    if (listItems != null)
                        foreach (SPListItem listItem in listItems)
                        {
                            try
                            {
                                Discussion discussion = new Discussion();
                                discussion = SPDataHelpers.MakeDiscussion(listItem);
                                discussion.NumberOfComments = listItem.Folder.SubFolders.Count;

                                discussions.Add(discussion);
                            }
                            catch (Exception ex)
                            {
                                ExceptionManager.HandleException(ex, false);
                            }
                        }

                    if (loadComments)
                    {
                        int count = 0;
                        foreach (SPListItem listItem in listItems)
                        {
                            discussions[count].NumberOfComments = listItem.Folder.SubFolders.Count;
                            if (discussions[count].NumberOfComments > 0)
                            {
                                foreach (SPFolder subFolder in listItem.Folder.SubFolders)
                                {
                                    try
                                    {
                                        int commentId = subFolder.Item.ID;
                                        discussions[count].Comments.Add(SPDataHelpers.MakeComment(list.Folders.GetItemById(commentId)));
                                    }
                                    catch (Exception ex)
                                    {
                                        ExceptionManager.HandleException(ex, false);
                                    }
                                }
                            }
                            count++;
                        }
                    }
                }
            }

            return discussions;
        }

        public List<Discussion> GetRecentDiscussions ( Guid siteCollectionId, string serverRelativeUrl) 
        {
            List<Discussion> discussions = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    StringBuilder queryText = new StringBuilder ( );
                    queryText.Append ( "<Where>" );
                    queryText.Append ( "  <IsNotNull>" );
                    queryText.Append ( "    <FieldRef Name='" + DiscussionFieldNames.ItemId + "' />" );
                    queryText.Append ( "  </IsNotNull>" );
                    queryText.Append ( "</Where>" );
                    queryText.Append ( "<OrderBy>" );
                    queryText.Append ( "  <FieldRef Name='" + DiscussionFieldNames.LastCommentDate + "' Ascending='false' />" );
                    queryText.Append ( "  <FieldRef Name='" + DiscussionFieldNames.CreatedDate + "' Ascending='false' />" );
                    queryText.Append ( "</OrderBy>" );

                    SPQuery query = new SPQuery ( );
                    query.RowLimit = 5;
                    query.Query = queryText.ToString ( );

                    SPList list = web.GetList ( SPHelpers.GetServerRelativeUrl ( web ) + Constants.SPListUrls.Discussions );

                    if ( list != null )
                    {
                        SPListItemCollection listItems = list.GetItems ( query );

                        if ( listItems != null && listItems.Count > 0 )
                        {
                            discussions = new List<Discussion> ( );
                            foreach ( SPListItem listItem in listItems )
                            {
                                Discussion discussion = new Discussion ( );
                                discussion = SPDataHelpers.MakeDiscussion ( listItem );
                                discussion.NumberOfComments = listItem.Folder.SubFolders.Count;
                                if ( discussion.NumberOfComments > 0 )
                                {
                                    List<Comment> comments = new List<Comment> ( );
                                    for ( int i = 0; i < listItem.Folder.SubFolders.Count; i++ )
                                    {
                                        SPFolder folder = listItem.Folder.SubFolders [ i ];
                                        Comment comment = new Comment ( );
                                        comment.Id = i;
                                        comment.ModifiedDate = DateTime.Parse ( folder.Item [ Constants.CommentFieldNames.ModifiedDate ].ToString ( ) );
                                        comment.CreatedDate = DateTime.Parse ( folder.Item [ Constants.CommentFieldNames.CreatedDate ].ToString ( ) );
                                        comments.Add ( comment );
                                    }

                                    comments.Sort ( SPHelpers.CompareByModifiedDate );

                                    discussion.Comments.Add ( SPDataHelpers.MakeComment ( listItem.Folder.SubFolders [ comments [ 0 ].Id ].Item ) );
                                }
                                discussions.Add ( discussion );
                            }
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return discussions;
        }

        public Discussion Save ( Discussion discussion, Guid siteCollectionId, string serverRelativeUrl )
        {
            SPList list = null;
            SPListItem listItem = null;
            try
            {
                if ( discussion == null )
                    throw new Exception ( "Cannot SaveDiscussion() when Discussion entity is null" );

                if ( discussion.EditType != EditType.Unchanged )
                {
                    using (SPWeb web = SPHelpers.GetWeb(siteCollectionId, serverRelativeUrl))
                    {
                        list = web.Lists[Constants.SPListNames.Discussions];


                        if (list != null)
                        {
                            #region Get Item
                            listItem = discussion.EditType == EditType.Created ? list.Folders.Add() : list.Folders.GetItemById(discussion.Id);

                            switch (discussion.EditType)
                            {
                                case EditType.Created:

                                    listItem[Constants.DiscussionFieldNames.SiteCollectionId] = list.ParentWeb.Site.ID;

                                    if (discussion.CreatedBy != null && discussion.CreatedBy.Id > 0)
                                        listItem[DiscussionFieldNames.CreatedBy] = discussion.CreatedBy.Id;
                                    if (discussion.CreatedDate != null && discussion.CreatedDate != DateTime.MinValue)
                                        listItem[DiscussionFieldNames.CreatedDate] = discussion.CreatedDate;
                                    if (discussion.ModifiedBy != null && discussion.ModifiedBy.Id > 0)
                                        listItem[DiscussionFieldNames.ModifiedBy] = discussion.ModifiedBy.Id;
                                    if (discussion.ModifiedDate != null && discussion.ModifiedDate != DateTime.MinValue)
                                        listItem[DiscussionFieldNames.ModifiedDate] = discussion.ModifiedDate;

                                    break;

                                case EditType.Updated:
                                    if (discussion.ModifiedBy != null && discussion.ModifiedBy.Id > 0)
                                        listItem[DiscussionFieldNames.ModifiedBy] = discussion.ModifiedBy.Id;
                                    if (discussion.ModifiedDate != null && discussion.ModifiedDate != DateTime.MinValue)
                                        listItem[DiscussionFieldNames.ModifiedDate] = discussion.ModifiedDate;
                                    break;

                                case EditType.Deleted:
                                default:
                                    break;
                            }
                            #endregion

                            #region Set Item Properties

                            if (listItem != null && discussion.EditType != EditType.Deleted)
                            {
                                if (!string.IsNullOrEmpty(discussion.Title))
                                    listItem[DiscussionFieldNames.Title] = discussion.Title;

                                if (!string.IsNullOrEmpty(discussion.Description))
                                    listItem[DiscussionFieldNames.Description] = discussion.Description;

                                if (!string.IsNullOrEmpty(discussion.Text))
                                    listItem[DiscussionFieldNames.Text] = discussion.Text;

                                if (!string.IsNullOrEmpty(discussion.HTMLText))
                                    listItem[DiscussionFieldNames.HTMLText] = discussion.HTMLText;

                                if (discussion.ModifiedDate != null && discussion.ModifiedDate > DateTime.MinValue)
                                    listItem[DiscussionFieldNames.LastCommentDate] = discussion.ModifiedDate;
                                else if (discussion.CreatedDate != null && discussion.CreatedDate > DateTime.MinValue)
                                    listItem[DiscussionFieldNames.LastCommentDate] = discussion.CreatedDate;

                                SPDataHelpers.PopulateCustomFieldsInListItemFromEntity(listItem, discussion);
                            }
                            #endregion

                            #region Update / Delete Item
                            try
                            {
                                list.ParentWeb.AllowUnsafeUpdates = true;
                                if (discussion.EditType == EditType.Deleted)
                                {
                                    list.Folders.DeleteItemById(listItem.ID);
                                }
                                else
                                {
                                    listItem.Update();
                                    listItem = list.Folders.GetItemById(listItem.ID);
                                    discussion.Id = listItem.ID;
                                    if (string.IsNullOrEmpty(discussion.ServerRelativeUrl))
                                        discussion.ServerRelativeUrl = listItem.Folder.ServerRelativeUrl;
                                }
                            }
                            catch (Exception ex)
                            {
                                ExceptionManager.HandleException(ex, true);
                            }
                            finally
                            {
                                list.ParentWeb.AllowUnsafeUpdates = false;
                            }
                            #endregion
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return discussion;
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.DataAccess/DiscussionDA.cs $
 * 
 * 19    2/08/10 5:04p Camerons
 * 
 * 18    1/25/10 1:17p Camerons
 * 
 * 17    1/12/10 12:02p Camerons
 * 
 * 16    26/11/09 10:35a Camerons
 * 
 * 15    24/11/09 10:55a Shafia
 * Discussion now stores the HTML format of the discussion text and uses
 * the WMD editor
 * 
 * 14    17/11/09 6:46p Camerons
 * 
 * 13    23/10/09 2:38p Shafia
 * 
 * 12    16/10/09 10:29a Shafia
 * 
 * 11    16/10/09 9:52a Shafia
 * when loading comments all comments were loaded to the first discussion
 * that is indexed at 0. 
 * 
 * 10    30/09/09 9:16a Shafia
 * 
 * 9     22/09/09 6:03p Camerons
 * Code changes to support creating user on demand - version 1.1.x.x
 * 
 * 8     17/08/09 10:41a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/